<?php


namespace App\Http\Library;


use OSS\Core\OssException;
use OSS\OssClient;

class AliOss
{
    private static $init = [];


    public static function getUploadParam()
    {

        $key = '<yourAccessKeySecret>';     // 请填写您的AccessKeySecret。
        // $callbackUrl为上传回调服务器的URL，请将下面的IP和Port配置为您自己的真实URL信息。
        $callbackUrl = 'http://88.88.88.88:8888/aliyun-oss-appserver-php/php/callback.php';
        $dir = 'user-dir-prefix/';          // 用户上传文件时指定的前缀。

        $callback_param = array(
            'callbackUrl'      => $callbackUrl,
            'callbackBody'     => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
            'callbackBodyType' => "application/x-www-form-urlencoded"
        );
        $callback_string = json_encode($callback_param);

        $base64CallbackBody = base64_encode($callback_string);
        $now = time();
        $expire = 30;  //设置该policy超时时间是10s. 即这个policy过了这个有效时间，将不能访问。
        $end = $now + $expire;
        $expiration = gmt_iso8601($end);


        //最大文件大小.用户可以自己设置
        $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
        $conditions[] = $condition;

        // 表示用户上传的数据，必须是以$dir开始，不然上传会失败，这一步不是必须项，只是为了安全起见，防止用户通过policy上传到别人的目录。
        $start = [0 => 'starts-with', 1 => '$key', 2 => $dir];
        $conditions[] = $start;
        $arr = ['expiration' => $expiration, 'conditions' => $conditions];
        $policy = json_encode($arr);
        $base64Policy = base64_encode($policy);
        $stringToSign = $base64Policy;
        $signature = base64_encode(hash_hmac('sha1', $stringToSign, $key, true));

        return [
            /*OSS获得的AccessKeyId*/
            'accessid'  => self::attr('access_key_id'),
            /*选定的OSS数据中心访问域名，例如oss-cn-hangzhou.aliyuncs.com*/
            'host'      => self::attr('endpoint'),
            /*策略*/
            'policy'    => $base64Policy,
            'signature' => $signature,
            'expire'    => $end,
            /*文件上传成功后的回调地址*/
            'callback'  => $base64CallbackBody,
        ];
    }


    /**
     * 阿里云:生成下载/上传的签名URL
     * 使用签名URL临时授权: https://help.aliyun.com/document_detail/32106.html?spm=a2c4g.11186623.6.1288.7c554e97TkMIM0
     * PutObject: https://help.aliyun.com/document_detail/31978.html?spm=a2c4g.11186623.6.1665.6d013cecce71MB
     * 在Header中包含签名: https://help.aliyun.com/document_detail/31951.html?spm=a2c4g.11186623.2.24.27bf250bi9p8Iw#concept-aml-vv2-xdb
     *
     * @param string $fileName    上传OSS时设置的文件名称
     * @param int    $timeout     URL失效时间(秒),默认60秒失效
     * @param string $method      URL访问方式:GET 下载、PUT 上传
     * @param string $contentType 上传文件类型,如果为空,则文件上传时也不可以指定.否则会提示签名匹配失败
     *
     * @return string
     * @throws OssException
     */
    public static function signUrl(string $fileName, $timeout = 60, $method = 'GET', $contentType = null)
    {
        $ossClient = new OssClient(self::attr('access_key_id'), self::attr('access_key_secret'), self::attr('endpoint'));
        $methodObj = [
            /*生成下载的签名URL*/
            'GET' => OssClient::OSS_HTTP_GET,
            /*生成上传的签名URL*/
            'PUT' => OssClient::OSS_HTTP_PUT
        ];
        $options = null;
        if (!empty($contentType)) {
            $options[OssClient::OSS_HEADERS][OssClient::OSS_CONTENT_TYPE] = $contentType;
        }
        return $ossClient->signUrl(self::attr('bucket'), $fileName, $timeout, $methodObj[$method], $options);
    }


    /**
     * 阿里云-下载文件到本地磁盘
     * https://help.aliyun.com/document_detail/88494.html?spm=a2c4g.11186623.6.1256.709c19aezYAjpF
     *
     * @param string $fileName 上传OSS时设置的文件名称
     * @param string $filePath 本地指定的文件路径加文件名包括后缀组成,例如/users/local/myfile.txt
     * @param string $etag     上传OSS,上传接口返回的文件etag
     *
     * @return string
     * @throws OssException
     */
    public static function downDisk(string $fileName, string $filePath, $etag = null)
    {
        $options = [
            OssClient::OSS_FILE_DOWNLOAD => $filePath,
        ];
        if (!empty($etag)) {
            /*如果指定的ETag和OSS文件的ETag匹配，则正常传输文件，否则返回错误（412 Precondition failed）*/
            $options[OssClient::OSS_HEADERS][OssClient::OSS_IF_MATCH] = $etag;
        }
        $ossClient = new OssClient(self::attr('access_key_id'), self::attr('access_key_secret'), self::attr('endpoint'));
        return $ossClient->getObject(self::attr('bucket'), $fileName, $options);
    }


    /**
     * 阿里云OSS-下载文件到内存
     * https://help.aliyun.com/document_detail/88495.html?spm=a2c4g.11186623.6.1257.67ab4f62aEhbV6
     *
     * @param string $fileName 上传OSS时设置的文件名称
     * @param string $etag     上传OSS,上传接口返回的文件etag
     *
     * @return string   返回文件内容
     * @throws OssException
     */
    public static function downRam(string $fileName, $etag = null)
    {
        $options = null;
        if (!empty($etag)) {
            /*如果指定的ETag和OSS文件的ETag匹配，则正常传输文件，否则返回错误（412 Precondition failed）*/
            $options[OssClient::OSS_HEADERS][OssClient::OSS_IF_MATCH] = $etag;
        }
        $ossClient = new OssClient(self::attr('access_key_id'), self::attr('access_key_secret'), self::attr('endpoint'));
        return $ossClient->getObject(self::attr('bucket'), $fileName, $options);
    }


    /**
     * 阿里云OSS-上传文件
     * https://help.aliyun.com/document_detail/88473.html?spm=a2c4g.11186623.6.1250.6c5f7c8bLxpQ6Y
     *
     * @param string $fileName 上传OSS时设置的文件名称
     * @param string $filePath 文件路径
     *
     * @throws OssException
     */
    public static function uploadFile(string $fileName, string $filePath)
    {
        $ossClient = new OssClient(self::attr('access_key_id'), self::attr('access_key_secret'), self::attr('endpoint'));
        $info = $ossClient->uploadFile(self::attr('bucket'), $fileName, $filePath);
        return [
            'etag'            => $info['etag'],
            'content-md5'     => $info['content-md5'],
            'oss-request-url' => $info['oss-request-url'],
            'Content-Type'    => $info['oss-requestheaders']['Content-Type'],
            'object'          => $fileName
        ];
    }


    /**
     * 获取指定属性
     *
     * @param null $key
     *
     * @return array|mixed|null
     */
    private static function attr($key = null)
    {
        if (empty(self::$init)) {
            self::$init = [
                'endpoint'          => config('alioss.endpoint'),
                'access_key_id'     => config('alioss.access_key_id'),
                'access_key_secret' => config('alioss.access_key_secret'),
                'bucket'            => config('alioss.bucket'),
                'callback_url'      => config('alioss.callback_url'),
            ];
        }
        if (isset(self::$init[$key])) {
            return self::$init[$key];
        }
        if (!empty($key)) {
            return null;
        }
        return self::$init;
    }


    /**
     * 时间ISO8601格式
     *
     * @param int $time int类型时间戳
     *
     * @return string
     */
    private static function gmtIso8601(int $time)
    {
        $dtStr = date("c", $time);
        $mydatetime = new DateTime($dtStr);
        $expiration = $mydatetime->format(DateTime::ISO8601);
        $pos = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);
        return $expiration . "Z";
    }


}





/**
 * AliOss.php
 *
 * 说明:
 * composer安装SDK：composer require aliyuncs/oss-sdk-php
 *
 * 修改历史
 * ----------------------------------------
 * 2020/12/22 10:39:00   操作:创建
 **/
